package com.bjl.service.imp;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bjl.dao.LotteryDao;
import com.bjl.dao.RoomDao;
import com.bjl.entity.User;
import com.bjl.service.LotteryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import orm.base.Ex.BaseServiceEx;
import orm.dictionary.BetOpening;
import orm.dictionary.Role;
import orm.dictionary.WinType;
import orm.utils.ChartUtils;
import orm.utils.ImageUtil;
import orm.utils.PictureUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.*;

/**
 * Created by ashin on 2017/12/8.
 */
@Service
@Scope("prototype")
public class LotteryServiceImp extends BaseServiceEx implements LotteryService {

    @Autowired
    LotteryDao lotteryDao;

    @Autowired
    ChartUtils chartUtils;

    @Autowired
    RoomDao roomDao;

    @Autowired
    PictureUtils pictureUtils;


    @Value("#{configProperties['SERV_URL']}")
    private String SERV_URL;

    @Override
    public void init() {
        super.init(lotteryDao);
    }

    @Override
    public String doGetRoomIssue(Map map) throws Exception {
        map.put("createTime", now());
        int count = lotteryDao.getLotteryCount(map);
        return autoGenericCode(count++, 4);
    }

    @Override
    public JSONObject queryPastLotteryInfo(Map map, HttpSession session) throws Exception {
        User user = (User) session.getAttribute("user");
        map.put("uId", user.getId());
        return this.codeData(lotteryDao.queryPastLotteryInfo(map));
    }

    @Override
    public JSONObject getOpenTime(Map map, HttpSession session) throws Exception {
        Map createTimeMap = lotteryDao.getOpenTime(map);
        String createTime = createTimeMap.get("createTime").toString();
        Calendar c = Calendar.getInstance();//可以对每个时间域单独修改
        Calendar now = Calendar.getInstance();//可以对每个时间域单独修改
        c.setTime(createTime == null ? sdf.parse(lotteryDao.getFirstOpenTime(map)) : sdf.parse(createTime));
        c.add(Calendar.MINUTE, 1);//1分钟后
//        int year = c.get(Calendar.YEAR);
//        int month = c.get(Calendar.MONTH) + 1;
//        int date = c.get(Calendar.DATE);
//        int hour = c.get(Calendar.HOUR_OF_DAY);
//        int minute = c.get(Calendar.MINUTE);
//        int second = c.get(Calendar.SECOND);
//        map = new HashMap();
//        map.put("enterTime", year + "-" + autoGenericCode(month, 2) + '-' + autoGenericCode(date, 2) + " " + autoGenericCode(hour, 2) + ":" + autoGenericCode(minute, 2) + ":" + autoGenericCode(second, 2));
//        if (minute == 59) {
//            minute = 0;
//            if (hour == 23) {
//                hour = 0;
//                if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
//                    if (date == 31 && month == 12) {
//                        date = 0;
//                        year += 1;
//                    } else if (date == 31)
//                        date = 0;
//                    else
//                        date += 1;
//                } else if (month == 4 || month == 6 || month == 9 || month == 11) {
//                    if (date == 30)
//                        date = 0;
//                    else
//                        date += 1;
//                } else if (month == 2) {
//                    //判斷閏年
//                    if (leapyear(year)) {
//                        if (date == 29)
//                            date = 0;
//                        else
//                            date += 1;
//                    } else {
//                        if (date == 28)
//                            date = 0;
//                        else
//                            date += 1;
//                    }
//                }
//            } else
//                hour += 1;
//        } else {
//            minute += 1;
//        }
//
//        map.put("endTime", year + "-" + autoGenericCode(month, 2) + '-' + autoGenericCode(date, 2) + " " + autoGenericCode(hour, 2) + ":" + autoGenericCode(minute, 2) + ":00");
        map.put("isBetOpening",createTimeMap.get("isBetOpening"));
        map.put("enterTime", sdf.format(now.getTime()));
        map.put("endTime", sdf.format(c.getTime()));
        return this.codeData(map);
    }

    /**
     * 不够位数的在前面补0，保留num的长度位数字
     *
     * @param code
     * @return
     */
    private static String autoGenericCode(int code, int num) {
        String result = "";
        // 保留num的位数
        // num 代表长度为4
        // d 代表参数为正数型
        result = String.format("%0" + num + "d", code);

        return result;
    }

    public static boolean leapyear(int year) {

        if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
            return true;
        else
            return false;
    }

    @Transactional
    @Override
    public JSONObject insertp(Map param, HttpSession session, HttpServletRequest request) throws Exception {
        User user = (User) session.getAttribute("user");
        String role = user.getRole();
        if (!String.valueOf(Role.ow).equals(role) && !String.valueOf(Role.admin).equals(role))
            return this.codeMess(eCode, "抱歉，您的权限不足");
        String issue = doGetRoomIssue(param);
        //期号
        param.put("issue", yymmdd.format(new Date()) + issue);
        //开奖号码（中文转英文）
        JSONObject jsonObject = JSON.parseObject(param.get("openCode").toString());
        JSONArray arrayZ = jsonObject.getJSONArray("z");
        JSONArray arrayX = jsonObject.getJSONArray("x");
        if (arrayZ.size() == 0) {
            return this.codeMess(eCode, "庄家没有牌");
        }
        if (arrayX.size() == 0) {
            return this.codeMess(eCode, "闲家没有牌");
        }

        //庄
        Map zMap = new HashMap();
        int z = getPoint(arrayZ);
        zMap.put("点数", getPoint(arrayZ));

        //闲
        Map xMap = new HashMap();
        int x = getPoint(arrayX);
        xMap.put("点数", getPoint(arrayX));

        //贏家
        Map winMap = new HashMap();
        winMap.put("赢家", z > x ? (checkIsHaveSameEle(arrayZ) ? "庄对" : "庄赢") : (checkIsHaveSameEle(arrayX) ? "闲对" : "闲赢"));
        if (z == x)
            winMap.put("赢家", "和");

        //赢家
        param.put("winner", resultChinToEnglis(winMap.get("赢家").toString()));
        //庄 扑克牌地址
        List zPkp = formPkpPath(arrayZ);

        //闲 扑克牌地址
        List xPkp = formPkpPath(arrayX);


        //返回 一个 网络地址，一个本地地址
        String[] uriArr = saveImage(pictureUtils.drawPic(zMap, xMap, winMap, zPkp, xPkp), request);

        if (uriArr == null)
            return this.codeMess(eCode, "生成图片失败!");
        else {
            param.put("imgUrl", uriArr[0]);
            Map resultMap = new HashMap();
            //生成圖片
            resultMap.put("imageUri", uriArr[0]);
            resultMap.put("content", uriArr[1]);
            resultMap.put("fromUserId", ((User) session.getAttribute("user")).getChart_token());
            resultMap.put("groupId", param.get("roomId").toString());
            //生成开奖视频
            resultMap.put("videoUrl", param.get("videoUrl").toString());
            resultMap.put("issue", "第" + issue + "期开奖结果");
            //验证中奖情况
            if (!validateAllIsWin(param))
                return this.codeMess(eCode, "开奖失败,验证中奖情况失败");

            String url = "http://" + request.getServerName() //服务器地址
                    + ":"
                    + request.getServerPort() + "/res/images/serverImgs/";

            //本地項目路徑
            String base_path = request.getSession().getServletContext().getRealPath("") + "/public/images/serverImgs/";

            //保存本期开奖结果
            lotteryDao.insertp(param);

            //批量发送
            sendAllResult(resultMap, param, base_path, url);

            return this.codeMess(sCode, "消息发送成功");
        }
    }

    /**
     * 结果英文转中文
     *
     * @return
     */
    private String resultChinToEnglis(String result) {
        if (result.equals("庄赢"))
            return "z";
        else if (result.equals("庄对"))
            return "zd";
        else if (result.equals("闲赢"))
            return "x";
        else if (result.equals("闲对"))
            return "xd";
        else
            return "h";
    }

    /**
     * 獲得點數
     *
     * @param array
     * @return
     */
    private int getPoint(JSONArray array) {
        int z = 0;
        for (int i = 0; i < array.size(); i++) {
            String strZ = array.getString(i);
            int intZ = toInt(strZ.substring(1));
            if (intZ > 9)
                intZ = 0;
            z += intZ;
        }
        return z % 10;
    }

    /**
     * 判斷是否有相同的元素
     *
     * @param arr
     * @return
     */
    private boolean checkIsHaveSameEle(JSONArray arr) {
        String[] list = arr.toArray(new String[]{});
        boolean flag = false;
        for (int i = 0; i < list.length - 1; i++) {
            for (int j = i + 1; j < list.length; j++) {
                if (list[i].substring(1).equals(list[j].substring(1))) {
                    flag = true;
                    break;
                }
            }
        }
        return flag;
    }

    private List formPkpPath(JSONArray jsonArray) {
        List list = new ArrayList();
        for (int i = 0; i < jsonArray.size(); i++) {
            Map pkpMap = new HashMap();
            String pkpName = jsonArray.getString(i);
            String pkpPath = this.getClass().getResource("/pkp/" + pkpName + ".png").getPath();
            pkpMap.put("path", pkpPath);
            list.add(pkpMap);
        }
        return list;
    }

    /**
     * 验证开奖
     *
     * @param map 开奖信息
     * @return
     * @throws Exception
     */
    private boolean validateAllIsWin(Map map) throws Exception {
        /*
         * 下注庄家而庄赢者，赢1赔1，另扣5%佣给庄家。
         * 下注闲家而闲赢者，赢1赔1。
         * 下注和局（即最终点数一样者），赢1赔8。
         * 下注对子（即庄或闲首两张牌为同数字或英文字母者），赢1赔11。
         */
        double winPercent;
        String winner = map.get("winner").toString();
        if (winner.equals("z")) {
            winPercent = 0.95d;
        } else if (winner.equals("x")) {
            winPercent = 1d;
        } else if (winner.equals("h")) {
            winPercent = 8d;
        } else {
            winPercent = 11d;
        }
        map.put("winPercent", winPercent);
        map.put("isWin", String.valueOf(WinType.win));
        map.put("betInfo", winner);
        //给所有中奖的派奖
        int ret = lotteryDao.validateAllisWin(map);
        //给所有不中奖的派奖
        Map notWinMap = new HashMap();
        notWinMap.put("issue", map.get("issue"));
        notWinMap.put("roomId", map.get("roomId"));
        notWinMap.put("noWinBetInfo", map.get("betInfo"));
        notWinMap.put("winPercent", 0);
        notWinMap.put("isWin", String.valueOf(WinType.nowWin));
        int ret2 = lotteryDao.validateAllisWin(notWinMap);
        if (ret == -1 || ret2 == -1)
            return false;
        else
            return true;
    }

    //获得扑克牌图片地址 是否是庄家
    private BufferedImage getPkpPath(JSONArray jsonArray, boolean isBanker) throws Exception {
        List<BufferedImage> pkpImages = new ArrayList();
        String bankerPath;
        if (isBanker) {
            bankerPath = this.getClass().getResource("/pkp/z.jpg").getPath();
        } else {
            bankerPath = this.getClass().getResource("/pkp/x.jpg").getPath();
        }
        BufferedImage bankerImage = ImageUtil.getBufferedImage(bankerPath);
        pkpImages.add(bankerImage);
        for (int i = 0; i < jsonArray.size(); i++) {
            String pkpName = jsonArray.getString(i);
            String pkpPath = this.getClass().getResource("/pkp/" + pkpName + ".png").getPath();
            BufferedImage image = ImageUtil.getBufferedImage(pkpPath);
            pkpImages.add(image);
        }
        //合并后的图片
        return ImageUtil.mergeImage(true, pkpImages.toArray(new BufferedImage[]{}));
    }

    //創建圖片
    private String[] saveImage(BufferedImage destImg, HttpServletRequest request) {
        String[] uri = new String[2];
        try {
            String base_path = request.getSession().getServletContext().getRealPath("") + "/uploadImg/";
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(new Date());
            String nyr = calendar.get(Calendar.YEAR) + "-" + (calendar.get(Calendar.MONTH) + 1) + "-" + calendar.get(Calendar.DAY_OF_MONTH);
            if (!new File(base_path).exists())
                new File(base_path).mkdir();
            base_path += "/" + nyr + "/";
            if (!new File(base_path).exists())
                new File(base_path).mkdir();
            long pre = System.currentTimeMillis();
            if (!ImageUtil.saveImage(destImg, base_path, pre + ".jpg", "jpg"))
                return null;
            else {

                String strBackUrl = "http://" + request.getServerName() //服务器地址
                        + ":"
                        + request.getServerPort();           //端口号
                //网络地址
                uri[0] = strBackUrl + "/uploadImg/" + nyr + "/" + pre + ".jpg";
                //本地地址
                uri[1] = base_path + pre + ".jpg";
                return uri;
            }
        } catch (Exception e) {
            logger.error("創建圖片失敗", e);
            return null;
        }
    }

    /**
     * 向指定房间发送结果(視頻)
     *
     * @return
     * @throws Exception
     */
    public boolean sendResult(Map resultMap) throws Exception {
        String[] groupIdArr = {resultMap.get("groupId").toString()};
        return chartUtils.sendMsg(groupIdArr, resultMap.get("fromUserId").toString(), resultMap);
    }

    /**
     * 向指定房间发送结果(圖片)
     *
     * @return
     * @throws Exception
     */
    public boolean sendImgResult(Map resultMap) throws Exception {
        String[] groupIdArr = {resultMap.get("groupId").toString()};
        return chartUtils.sendImgMsg(groupIdArr, resultMap.get("fromUserId").toString(), resultMap);
    }

    /**
     * 统一发布消息
     *
     * @param resultMap     发送结果
     * @param insertMap     新增的信息
     * @param localResource 本地路径
     * @param url           网络路径
     * @throws Exception
     */
    public void sendAllResult(final Map resultMap, final Map insertMap, final String localResource, final String url) throws Exception {
        //新开线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Map roomMap = new HashMap();
                    //更新房间为开奖中
                    roomMap.put("id",insertMap.get("roomId"));
                    roomMap.put("isBetOpening", String.valueOf(BetOpening.opening));
                    roomDao.updatep(roomMap);

                    String[] groupIdArr = {resultMap.get("groupId").toString()};
                    Map imgMap = new HashMap();
                    imgMap.put("content", localResource + "stop.jpg");
                    imgMap.put("imageUri", url + "stop.png");
                    //即将开奖标识
                    imgMap.put("extra", "{\"info\":\"betOpening\"}");
                    chartUtils.sendImgMsg(groupIdArr, resultMap.get("fromUserId").toString(), imgMap);
                    //停1秒
                    Thread.sleep(2000);
                    //倒数5秒
                    imgMap = new HashMap();
                    for (int i = 5; i >= 0; i--) {
                        //即将开奖的标识
                        imgMap.put("content", localResource + i + ".jpg");
                        imgMap.put("imageUri", url + i + ".png");
                        chartUtils.sendImgMsg(groupIdArr, resultMap.get("fromUserId").toString(), imgMap);
                        //停1秒
                        Thread.sleep(1000);
                    }

                    imgMap = new HashMap();
                    //开奖标识
                    imgMap.put("content", localResource + "open.jpg");
                    imgMap.put("imageUri", url + "open.png");
                    chartUtils.sendImgMsg(groupIdArr, resultMap.get("fromUserId").toString(), imgMap);

                    //停1秒
                    Thread.sleep(2000);

                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("info", "BetOpen");
                    jsonObject.put("issue", insertMap.get("issue").toString());
                    Map txtMap = new HashMap();
                    txtMap.put("extra", jsonObject.toJSONString());
                    //发送图文以及视频
                    sendResult(resultMap);
                    sendImgResult(resultMap);
                    txtMap.put("betInfo", insertMap.get("issue").toString() + "期赢家为：" + kjResult(insertMap.get("winner").toString()));
                    chartUtils.sendTxtMsg(groupIdArr, resultMap.get("fromUserId").toString(), txtMap);

                    Thread.sleep(5000);

                    //更新房间为开奖中
                    roomMap.put("id",insertMap.get("roomId"));
                    roomMap.put("isBetOpening", String.valueOf(BetOpening.notOpening));
                    roomDao.updatep(roomMap);

                    imgMap = new HashMap();
                    //提示下一轮开始
                    imgMap.put("content", localResource + "backwards.jpg");
                    imgMap.put("imageUri", url + "backwards.png");
                    imgMap.put("extra", "{\"info\":\"nextBetBegin\"}");
                    chartUtils.sendImgMsg(groupIdArr, resultMap.get("fromUserId").toString(), imgMap);

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

}

